#include "Frame.h"
#include "diagram.h"

#include <iostream>
#include <string>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"ws2_32")
#include <string>
#include <queue>
#include <vector>
#include <fstream>
#include <map>
using namespace std;

const int PORT = 3400;
const int LIMIT = 20;
const int MAX_LEN = 250;
const int BUF_LEN = 300;

struct sockaddr_in server, client[LIMIT+2];

HANDLE hThread[LIMIT+2];
DWORD dwThreadId[LIMIT+2];

SOCKET s[LIMIT+1];

map<string, string> users;
map<string, bool> active;

bool QUIT = false;

void LoadUserData()
{
	ifstream fin((ROOT + USER).c_str());
	string name, password;
	while (fin >> name)
	{
		fin >> password;
		users[name] = password;
		active[name] = false;
	}
	fin.close();
}

vector<string> MySplit(string s, char deli)
{
    vector<string> ret;
    
    int i = 0, j = 0;
    while (i < s.size())
    {
        for (j = i; j < s.size() && s[j] != deli; j++);
        ret.push_back(s.substr(i, j - i));
        i = j + 1;
    }
    
    return ret;
}

void MySend(SOCKET socket, string s) 
{
	send(socket, s.c_str(), s.size() + 1, 0);
}

string MyRecv(SOCKET socket)
{
	char buf[BUF_LEN];
	memset(buf, 0, sizeof buf);
	recv(socket, buf, MAX_LEN, 0);
	return string(buf);
}

// the thread to receive
DWORD WINAPI ThreadProc2(LPVOID lpParam)
{
	int k = *((int*)lpParam);
	int ret = sizeof(client[k]);
	s[k] = accept(s[0], (struct sockaddr *)&client[k], &ret);

	if (s[k]==INVALID_SOCKET)
	{
		std::cout << "Error Accept" << std::endl;
	}
	else
	{
		int id = 1;
		for (; id <= LIMIT && s[id] != NULL; ++id);
		if (id <= LIMIT)
		{
			hThread[id] = ::CreateThread(NULL, NULL, ThreadProc2, &id, 0, &dwThreadId[id]);
		}
		
		printf("[+] Connection accepted from %s:%d\n",
					inet_ntoa(client[k].sin_addr), ntohs(client[k].sin_port));

		Frame* frame = new Frame();
		frame->socket = s[k];
		frame->username = "";
		frame->bye = false;


		char buf[BUF_LEN];
		ret = 0;
		while (ret != SOCKET_ERROR && !QUIT && !frame->bye)
		{
			memset(buf, 0, sizeof buf);
			ret = recv(s[k], buf, MAX_LEN, 0);
			if (ret != SOCKET_ERROR)
			{
				// Do something!
				printf("%s\n", buf);

				frame->cmd = string(buf);
				frame->parsed = MySplit(frame->cmd, ':');

				if (frame->username.empty() && frame->parsed[0] != "login" && frame->parsed[0] != "register") {
					MySend(frame->socket, frame->parsed[0] + FAILURE + "Not logged in.");
					continue;
				}

				if (frame->cmd.substr(0, 6) == "create") {
					frame->OnFileNew();
				}
				else if (frame->cmd.substr(0, 4) == "save") {
					frame->OnFileSave();
				}
				else if (frame->cmd.substr(0, 4) == "open") {
					frame->OnFileOpen();
				}
				else if (frame->cmd.substr(0, 6) == "delete") {
					frame->OnItemDelete();
				}
				else if (frame->cmd.substr(0, 4) == "sort") {
					frame->Sort();
				}
				else if (frame->cmd.substr(0, 6) == "search") {
					frame->OnItemFind();
				}
				else if (frame->cmd.substr(0, 6) == "insert") {
					frame->OnItemAdd();
				}
				else if (frame->cmd.substr(0, 6) == "update") {
					frame->OnItemUpdate();
				}
				else if (frame->parsed[0] == "login") {
					frame->Login();
				}
				else if (frame->parsed[0] == "register") {
					frame->Register();
				}
				else if (frame->parsed[0] == "exit") {
					frame->Logout();
				}
				else if (frame->parsed[0] == "home") {
					frame->OnHome();
				}
				else if (frame->parsed[0] == "end") {
					frame->OnEnd();
				}
				else if (frame->parsed[0] == "pageup") {
					frame->OnPageup();
				}
				else if (frame->parsed[0] == "pagedown") {			
					frame->OnPagedown();
				}
			}
		}

		if (!frame->username.empty())
			active[frame->username] = false;

		std::cout << k << " disconnected." << std::endl;
		closesocket(s[k]);
		s[k] = NULL;
	}

	return 0;
}

int main()
{
	int ret;
	std::string cmd;

	LoadUserData();

	WSADATA wsd;
	if (WSAStartup(MAKEWORD(1,1), &wsd) != 0) {
		printf("[-] WSAStartup error:%d\n", WSAGetLastError());
		return 1;
	}

	s[0] = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

	server.sin_family = AF_INET;
	server.sin_port = htons(PORT);
	server.sin_addr.s_addr= 0;

	ret = bind(s[0], (struct sockaddr *)&server, sizeof(server));
	ret = listen(s[0], 100);
	printf("[+] Listen on TCP %d.\n", PORT);

	int t = 1;
	hThread[t] = ::CreateThread (NULL, NULL, ThreadProc2, &t, 0, &dwThreadId[t]);

	while (!QUIT)
	{
		std::cin >> cmd;
		if (cmd == "QUIT")
		{
			break;
		}

	}

	Sleep(1000);

	WSACleanup();

	return 0;
}